﻿using System;
using System.Collections.Generic;
using Protocol.Constant;
using Protocol.Dto.Fight;

namespace PokerServer.Cache.Fight
{
    /// <summary>
    /// 战斗房间
    /// </summary>
    public class FightRoom
    {
        //******************* Attribute
        // 房间id
        public int Id { get; private set; }

        // 所有的玩家
        public List<PlayerDto> PlayerList { get; private set; }

        // 中途离开的玩家
        public List<int> LeaveUIdList { get; private set; }

        // 牌库
        public LibraryModel LibraryModel { get; private set; }

        // 底牌
        public List<CardDto> TableCardList { get; private set; }

        // 倍数
        public int Multiple { get; private set; }

        // 回合管理类
        public RoundModel RoundModel { get; private set; }


        public FightRoom(int id, List<int> uidList)
        {
            InitVariable(id);

            foreach (int uid in uidList)
            {
                PlayerDto playerDto = new PlayerDto(uid);
                PlayerList.Add(playerDto);
            }
        }

        private void InitVariable(int id)
        {
            Id = id;
            PlayerList = new List<PlayerDto>();
            LeaveUIdList = new List<int>();
            LibraryModel = new LibraryModel();
            TableCardList = new List<CardDto>();
            Multiple = 1;
            RoundModel = new RoundModel();
        }

        public void Init(List<int> uIdList)
        {
            foreach (int id in uIdList)
            {
                PlayerDto playerDto = new PlayerDto(id);
                PlayerList.Add(playerDto);
            }
        }


        public int Turn()
        {
            int currUid = RoundModel.CurrentUid;
            int nextUid = GetNextUid(currUid);

            RoundModel.CurrentUid = nextUid;

            return nextUid;
        }


        // 计算下一个出牌者
        public int GetNextUid(int currentUid)
        {
            for (int i = 0; i < PlayerList.Count; i++)
            {
                if (PlayerList[i].userId == currentUid)
                {
                    if (i == 2)
                    {
                        return PlayerList[0].userId;
                    }
                    else
                    {
                        return PlayerList[i + 1].userId;
                    }
                }
            }

            // 好方法
            throw new Exception("并没有这个出牌者");
        }


        /// <summary>
        /// 判断玩家是否能出牌，并处理出牌逻辑
        /// </summary>
        /// <param name="type">出牌的类型 （单牌）</param>
        /// <param name="weight">牌的大小</param>
        /// <param name="length">牌的数量</param>
        /// <param name="userId">出牌人id</param>
        /// <param name="dtoList">出的牌对象</param>
        /// <returns></returns>
        public bool DeadCard(int type, int weight, int length, int userId, List<CardDto> dtoList)
        {
            bool canDeal = false;

            if (type == RoundModel.LastCardType && weight > RoundModel.LastWight)
            {
                // 特殊的类型， 顺子 长度一样， 比最小的一张
                if (type == CardType.STRAIGHT || type == CardType.DOUBLE_STRAIGHT || type == CardType.TRIPLE_STRAIGHT)
                {
                    if (length == RoundModel.LastLength)
                    {
                        // 满足出牌条件
                        canDeal = true;
                    }
                }
                else
                {
                    // 满足出牌条件
                    canDeal = true;
                }
            }
            // 普通的炸弹 可以压 任何不是炸弹的牌
            else if (type == CardType.BOOM && RoundModel.LastCardType != CardType.BOOM)
            {
                canDeal = true;
            }
            else if (type == CardType.JOKER_BOOM)
            {
                canDeal = true;
            }
            // 第一次出牌 或者自己就是最大的出牌者
            else if (userId == RoundModel.BiggestUId)
            {
                canDeal = true;
            }

            if (canDeal)
            {
                // 移除玩家的手牌
                RemoveUserCards(userId, dtoList);
                // 可能会翻倍
                if (type == CardType.BOOM)
                {
                    Multiple *= 2;
                }
                else if (type == CardType.JOKER_BOOM)
                {
                    Multiple *= 4;
                }

                // 保存回合信息
                RoundModel.Change(userId, length, weight, type);
            }

            return canDeal;
        }


        /// <summary>
        /// 获取玩家的手牌
        /// </summary>
        /// <param name="userId">玩家id</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public List<CardDto> GetUserCards(int userId)
        {
            foreach (PlayerDto dto in PlayerList)
            {
                if (dto.userId == userId)
                {
                    return dto.cardList;
                }
            }

            throw new Exception("不存在这个玩家");
        }


        /// <summary>
        /// 移除玩家手牌
        /// </summary>
        /// <param name="userId">玩家Id</param>
        /// <param name="_cardList">需要移除的牌</param>
        private void RemoveUserCards(int userId, List<CardDto> _cardList)
        {
            List<CardDto> currList = GetUserCards(userId);

            List<CardDto> list = new List<CardDto>();

            foreach (CardDto cardDto in _cardList)
            {
                for (int i = currList.Count - 1; i >= 0; i--)
                {
                    if (currList[i].Name == cardDto.Name)
                    {
                        list.Add(currList[i]);
                        break;
                    }
                }
            }

            foreach (CardDto cardDto in list)
            {
                currList.Remove(cardDto);
            }
        }


        /// <summary>
        /// 发牌
        /// </summary>
        public void InitPlayerCards()
        {
            // 54张
            // 一人17张
            for (int j = 0; j <= 2; j++)
            {
                for (int i = 0; i < 17; i++)
                {
                    CardDto card = LibraryModel.Deal();
                    if (card != null)
                    {
                        PlayerList[j].AddCard(card);
                    }
                }
            }

            // 留3张为底牌
            for (int i = 0; i < 3; i++)
            {
                CardDto card = LibraryModel.Deal();

                TableCardList.Add(card);
            }
        }

        /// <summary>
        /// 设置地主身份
        /// </summary>
        /// <param name="userId"></param>
        public void SetLandlord(int userId)
        {
            foreach (PlayerDto playerDto in PlayerList)
            {
                if (playerDto.userId == userId)
                {
                    playerDto.identity = Identity.LANDLORD;

                    // 给底牌给地主
                    foreach (CardDto t in TableCardList)
                    {
                        playerDto.AddCard(t);
                    }

                    // 添加底牌后在排一个序
                    Sort();

                    // 开始回合
                    // 地主先出牌
                    RoundModel.Start(userId);
                }
            }
        }


        /// <summary>
        /// 获取玩家的数据模型
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public PlayerDto GetPlayerDto(int userId)
        {
            foreach (PlayerDto playerDto in PlayerList)
            {
                if (playerDto.userId == userId)
                {
                    return playerDto;
                }
            }

            throw new Exception("没有这个玩家！ 获取不到数据");
        }

        /// <summary>
        /// 获取用户的身份
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public int GetPlayerIdentity(int userId)
        {
            return GetPlayerDto(userId).identity;
        }

        /// <summary>
        /// 获取相同身份的玩家
        /// </summary>
        /// <param name="identity"></param>
        /// <returns></returns>
        public List<int> GetSameIdentityUIds(int identity)
        {
            List<int> ids = new List<int>();

            foreach (PlayerDto playerDto in PlayerList)
            {
                if (playerDto.identity == identity)
                {
                    ids.Add(playerDto.userId);
                }
            }

            return ids;
        }

        /// <summary>
        /// 获取相同身份的玩家
        /// </summary>
        /// <param name="identity"></param>
        /// <returns></returns>
        public List<int> GetDifferentIdentityUIds(int identity)
        {
            List<int> ids = new List<int>();

            foreach (PlayerDto playerDto in PlayerList)
            {
                if (playerDto.identity != identity)
                {
                    ids.Add(playerDto.userId);
                }
            }

            return ids;
        }

        /// <summary>
        /// 获取房间里的第一个人
        /// </summary>
        /// <returns></returns>
        public int GetFirstUid()
        {
            return PlayerList[0].userId;
        }

        /// <summary>
        /// 排序手牌
        /// </summary>
        /// <param name="cardList"></param>
        /// <param name="asc"></param>
        private void SortCard(List<CardDto> cardList, bool asc = true)
        {
            cardList.Sort(
                delegate(CardDto a, CardDto b)
                {
                    if (asc)
                    {
                        return a.Weight.CompareTo(b.Weight);
                    }
                    else
                    {
                        return a.Weight.CompareTo(b.Weight) * -1;
                    }
                });
        }

        /// <summary>
        /// 排序 默认升序
        /// </summary>
        /// <param name="asc"></param>
        public void Sort(bool asc = true)
        {
            SortCard(PlayerList[0].cardList, asc);
            SortCard(PlayerList[1].cardList, asc);
            SortCard(PlayerList[2].cardList, asc);
            SortCard(TableCardList, asc);
        }

        /// <summary>
        /// 是否掉线了
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public bool IsOffLine(int userId)
        {
            return LeaveUIdList.Contains(userId);
        }
    }
}